home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_87 / swapstre.pas < prev    next >
Pascal/Delphi Source File  |  1995-01-01  |  15KB  |  584 lines

  1. {****************************************************************************}
  2. {                                                                            }
  3. { MODULE:         SwapStream                                                 }
  4. {                                                                            }
  5. { DESCRIPTION:    This UNIT implements a multi-stream Turbo Vision Stream.   }
  6. {                 TSwapStream is a stream that is constructed out of several }
  7. {                 other streams. It's primery and intended use consists in   }
  8. {                 providing a large platform for the swap-manager found in   }
  9. {                 the SwapManager UNIT.                                      }
  10. {                                                                            }
  11. {                 By default, this stream maps onto EMS and all hard drives  }
  12. {                 available, beginning with the TMP, TEMP and TMPDIR         }
  13. {                 environment variables, following with all drives from C:   }
  14. {                 to Z:, and finally the current drive. If a different       }
  15. {                 mapping is required, the InitStreams method should be      }
  16. {                 derived.                                                   }
  17. {                                                                            }
  18. { AUTHOR:         Juan Carlos Arévalo                                        }
  19. {                                                                            }
  20. { MODIFICATIONS:  Nobody (yet ;-)                                            }
  21. {                                                                            }
  22. { HISTORY:        17-Jan-1993 Definition and implementation.                 }
  23. {                                                                            }
  24. { (C) 1993 VangeliSTeam                                                      }
  25. {____________________________________________________________________________}
  26.  
  27. UNIT SwapStream;
  28.  
  29. {$I-}
  30.  
  31. INTERFACE
  32.  
  33. USES Dos, Objects, FileUtil, HexConversions;
  34.  
  35.  
  36.  
  37.  
  38. { Configuration. }
  39.  
  40. CONST
  41.   SwapUseEms   : BOOLEAN   = TRUE;
  42.   SwapQuanto   : WORD      = 4096;
  43.   SwapFName    : STRING[6] = 'VTSWAP';
  44.   SwapPrimPath : PathStr   = '';
  45.  
  46.  
  47.  
  48.  
  49. { New TDosStream. Stores the filename. }
  50.  
  51. TYPE
  52.   PMyDosStream = ^TMyDosStream;
  53.   TMyDosStream =
  54.     OBJECT(TDosStream)
  55.       FName : PathStr;
  56.  
  57.       CONSTRUCTOR Init(FileName: FNameStr; Mode: WORD);
  58.     END;
  59.  
  60.  
  61.  
  62.  
  63. { New TEmsStream. Fixes a bug in Truncate. }
  64.  
  65. TYPE
  66.   PMyEmsStream = ^TMyEmsStream;
  67.   TMyEmsStream =
  68.     OBJECT(TEmsStream)
  69.       MinSize : LONGINT;
  70.  
  71.       CONSTRUCTOR Init(AMinSize, AMaxSize : LONGINT);
  72.       PROCEDURE   Truncate;                         VIRTUAL;
  73.     END;
  74.  
  75.  
  76.  
  77.  
  78. { TSwapStream. Stream that maps onto a collection of streams. }
  79.  
  80. TYPE
  81.   PSwapStream = ^TSwapStream;
  82.   TSwapStream =
  83.     OBJECT(TStream)
  84.       StreamColl    : TCollection;
  85.       CurrentStream : INTEGER;
  86.       LastStream    : INTEGER;
  87.  
  88.  
  89.       CONSTRUCTOR Init;
  90.       DESTRUCTOR  Done; VIRTUAL;
  91.       PROCEDURE   InsertPath(p: PathStr);                 VIRTUAL;
  92.       PROCEDURE   InitStreams;                            VIRTUAL;
  93.  
  94.       FUNCTION  GetPos                         : LONGINT; VIRTUAL;
  95.       FUNCTION  GetSize                        : LONGINT; VIRTUAL;
  96.       PROCEDURE Seek    (SPos: LONGINT);                  VIRTUAL;
  97.       PROCEDURE Truncate;                                 VIRTUAL;
  98.       PROCEDURE Reset;                                    VIRTUAL;
  99.       PROCEDURE Read    (VAR Buf; Count: WORD);           VIRTUAL;
  100.       PROCEDURE Write   (VAR Buf; Count: WORD);           VIRTUAL;
  101.     END;
  102.  
  103.  
  104.  
  105.  
  106. IMPLEMENTATION
  107.  
  108.  
  109.  
  110.  
  111. {----------------------------------------------------------------------------}
  112. { Utility function. Shouldn't belong here. :-(                               }
  113. {____________________________________________________________________________}
  114.  
  115. PROCEDURE IncPtr(VAR p: POINTER; Count: WORD);
  116.   BEGIN
  117.     p := Ptr(Seg(p^), Ofs(P^) + Count);
  118.   END;
  119.  
  120.  
  121.  
  122.  
  123. {----------------------------------------------------------------------------}
  124. { TMyDosStream.                                                              }
  125. {____________________________________________________________________________}
  126.  
  127. CONSTRUCTOR TMyDosStream.Init(FileName: FNameStr; Mode: WORD);
  128.   BEGIN
  129.     TDosStream.Init(FileName, Mode);
  130.     FName := FileName;
  131.   END;
  132.  
  133.  
  134.  
  135.  
  136. {----------------------------------------------------------------------------}
  137. { TMyEmsStream.                                                              }
  138. {____________________________________________________________________________}
  139.  
  140. CONSTRUCTOR TMyEmsStream.Init(AMinSize, AMaxSize : LONGINT);
  141.   BEGIN
  142.     TEmsStream.Init(AMinSize, AMaxSize);
  143.     MinSize := AMinSize;
  144.   END;
  145.  
  146.  
  147. PROCEDURE TMyEmsStream.Truncate;                         
  148.   VAR
  149.     TPos : LONGINT;
  150.   BEGIN
  151.     IF Status = stOk THEN
  152.       BEGIN
  153.         TPos := GetPos;
  154.         IF TPos < MinSize THEN
  155.           BEGIN
  156.             Seek(MinSize);
  157.             TEmsStream.Truncate;
  158.             Seek(TPos);
  159.             Size := TPos;
  160.           END
  161.         ELSE
  162.           TEmsStream.Truncate;
  163.       END;
  164.   END;
  165.  
  166.  
  167.  
  168.  
  169. {----------------------------------------------------------------------------}
  170. { TSwapStream.                                                               }
  171. {____________________________________________________________________________}
  172.  
  173. CONSTRUCTOR TSwapStream.Init;
  174.   BEGIN
  175.     TStream.Init;
  176.     StreamColl.Init(3, 2);
  177.  
  178.     InitStreams;
  179.  
  180.     IF StreamColl.Count = 0 THEN
  181.       Error(stInitError, 0);
  182.  
  183.     CurrentStream := 0;
  184.     LastStream    := 0;
  185.   END;
  186.  
  187.  
  188. PROCEDURE TSwapStream.InitStreams;
  189.   VAR
  190.     Str     : PStream;
  191.     MyPath  : PathStr;
  192.     MyDrive : CHAR;
  193.     ch      : CHAR;
  194.   BEGIN
  195.     MyPath := ParamStr(0);
  196.     IF (Length(MyPath) >= 2) AND (MyPath[2] = ':') THEN
  197.       MyDrive := UpCase(MyPath[1])
  198.     ELSE
  199.       MyDrive := #0;
  200.  
  201.     IF SwapUseEms THEN
  202.       BEGIN
  203.         Str := New(PMyEmsStream, Init(16384, $7FFFFFFF));
  204.         IF Str^.Status <> stOk THEN
  205.           Dispose(Str, Done)
  206.         ELSE
  207.           StreamColl.Insert(Str);
  208.       END;
  209.  
  210.     IF SwapPrimPath <> '' THEN
  211.       InsertPath(SwapPrimPath);
  212.  
  213.     InsertPath(GetEnv('TMP'));
  214.     InsertPath(GetEnv('TEMP'));
  215.     InsertPath(GetEnv('TMPDIR'));
  216.     InsertPath(GetEnv('TEMPDIR'));
  217.  
  218.     FOR ch := 'C' TO 'Z' DO
  219.       IF ch <> MyDrive THEN
  220.         InsertPath(ch+':\');
  221.  
  222.     IF MyDrive > 'C' THEN
  223.       InsertPath(MyDrive+':\');
  224.   END;
  225.  
  226.  
  227. PROCEDURE TSwapStream.InsertPath(p: PathStr);
  228.   VAR
  229.     d   : DirStr;
  230.     i   : WORD;
  231.     r   : WORD;
  232.     fil : FILE;
  233.     Str : PStream;
  234.   BEGIN
  235.     KillBar2Path(p);
  236.     p := FExpand(p);
  237.  
  238.     FOR i := 1 TO StreamColl.Count DO
  239.       BEGIN
  240.         Str := PStream(StreamColl.At(i-1));
  241.         IF (TypeOf(Str^) = TypeOf(TMyDosStream))                AND
  242.            (UpCase(PMyDosStream(Str)^.FName[1]) = UpCase(p[1])) THEN
  243.           EXIT;
  244.       END;
  245.  
  246.     MakePath(p);
  247.     AddBar2Path(p);
  248.     d := p;
  249.     i := 0;
  250.     REPEAT
  251.  
  252.       p := d + SwapFName + HexByte(i)+'.$$$';
  253.       Assign(fil, p);
  254.       Erase(fil);
  255.       r := IOResult;
  256.       INC(i);
  257.  
  258.     UNTIL NOT FileExists(p);
  259.  
  260.     Str := New(PMyDosStream, Init(p, stCreate));
  261.  
  262.     IF Str^.Status <> stOk THEN
  263.       Dispose(Str, Done)
  264.     ELSE
  265.       StreamColl.Insert(Str);
  266.   END;
  267.  
  268.  
  269. DESTRUCTOR TSwapStream.Done; 
  270.  
  271.   PROCEDURE DeleteStream(Str: PStream); FAR;
  272.     VAR
  273.       f : File;
  274.     BEGIN
  275.       Str^.Seek(0);
  276.       Str^.Truncate;  { It's faster this way 8-O (DOS-Specific, of course) }
  277.  
  278.       IF TypeOf(Str^) = TypeOf(TMyDosStream) THEN
  279.         BEGIN
  280.           Assign(f, PMyDosStream(Str)^.FName);
  281.           Dispose(Str, Done);
  282.           Erase(f);
  283.         END
  284.       ELSE
  285.         Dispose(Str, Done);
  286.     END;
  287.  
  288.   BEGIN { Done }
  289.     StreamColl.ForEach(@DeleteStream);
  290.     TStream.Done;
  291.   END;
  292.  
  293.  
  294. FUNCTION TSwapStream.GetPos : LONGINT; 
  295.   VAR
  296.     i   : INTEGER;
  297.     Pos : LONGINT;
  298.   BEGIN
  299.     GetPos := -1;
  300.  
  301.     IF Status <> stOk THEN EXIT;
  302.     Reset;
  303.  
  304.     Pos := 0;
  305.     FOR i := 0 TO CurrentStream - 1 DO
  306.       BEGIN
  307.         INC(Pos, PStream(StreamColl.At(i))^.GetSize);
  308.       END;
  309.  
  310.     INC(Pos, PStream(StreamColl.At(CurrentStream))^.GetPos);
  311.  
  312.     GetPos := Pos;
  313.   END;
  314.  
  315.  
  316. FUNCTION TSwapStream.GetSize : LONGINT; 
  317.   VAR
  318.     i    : INTEGER;
  319.     Size : LONGINT;
  320.   BEGIN
  321.     GetSize := -1;
  322.  
  323.     IF Status <> stOk THEN EXIT;
  324.     Reset;
  325.  
  326.     Size := 0;
  327.     FOR i := 0 TO LastStream DO
  328.       BEGIN
  329.         INC(Size, PStream(StreamColl.At(i))^.GetSize);
  330.       END;
  331.  
  332.     GetSize := Size;
  333.   END;
  334.  
  335.  
  336. PROCEDURE TSwapStream.Seek (SPos: LONGINT);
  337.   VAR
  338.     Junk : BYTE ABSOLUTE 0:0;
  339.     Pos  : LONGINT;
  340.     Last : LONGINT;
  341.     Size : LONGINT;
  342.     i    : INTEGER;
  343.   BEGIN
  344.     IF Status <> stOk THEN EXIT;
  345.     Reset;
  346.  
  347.     Size := GetSize;
  348.     IF Size >= SPos THEN
  349.       BEGIN
  350.  
  351.         Pos  := 0;
  352.         Last := 0;
  353.         i    := 0;
  354.         WHILE (i <= LastStream) AND (Pos < SPos) DO
  355.           BEGIN
  356.             Last := PStream(StreamColl.At(i))^.GetSize;
  357.             IF Pos + Last < SPos THEN
  358.               BEGIN
  359.                 INC(i);
  360.                 INC(Pos, Last);
  361.               END
  362.             ELSE
  363.               BEGIN
  364.                 Last := SPos - Pos;
  365.                 Pos  := SPos;
  366.               END;
  367.           END;
  368.  
  369.         CurrentStream := i;
  370.         PStream(StreamColl.At(i))^.Seek(Last);
  371.  
  372.         IF PStream(StreamColl.At(i))^.Status <> stOk THEN
  373.           BEGIN
  374.             Error(PStream(StreamColl.At(i))^.Status, i);
  375.             EXIT;
  376.           END;
  377.  
  378.       END
  379.     ELSE
  380.       BEGIN
  381.         Pos := SPos - Size;
  382.         Seek(Size);
  383.         IF Status <> stOk THEN EXIT;
  384.  
  385.         FOR Last := 1 TO Pos DIV 32768 DO
  386.           BEGIN
  387.             Write(Junk, 32768);
  388.             IF Status <> stOk THEN EXIT;
  389.           END;
  390.  
  391.         IF (Pos MOD 32768) > 0 THEN 
  392.           Write(Junk, Pos MOD 32768);
  393.  
  394.         IF Status <> stOk THEN EXIT;
  395.       END;
  396.   END;
  397.  
  398.  
  399. PROCEDURE TSwapStream.Truncate;                              
  400.   VAR
  401.     i : INTEGER;
  402.   BEGIN
  403.     IF Status <> stOk THEN EXIT;
  404.     Reset;
  405.  
  406.     FOR i := LastStream DOWNTO CurrentStream + 1 DO
  407.       BEGIN
  408.         PStream(StreamColl.At(i))^.Seek(0);
  409.         PStream(StreamColl.At(i))^.Truncate;
  410.  
  411.         IF PStream(StreamColl.At(i))^.Status <> stOk THEN
  412.           BEGIN
  413.             LastStream := CurrentStream;
  414.             Error(PStream(StreamColl.At(i))^.Status, i);
  415.             EXIT;
  416.           END;
  417.  
  418.       END;
  419.  
  420.     PStream(StreamColl.At(CurrentStream))^.Truncate;
  421.  
  422.     IF PStream(StreamColl.At(CurrentStream))^.Status <> stOk THEN
  423.       Error(PStream(StreamColl.At(CurrentStream))^.Status, CurrentStream);
  424.  
  425.     LastStream := CurrentStream;
  426.   END;
  427.  
  428.  
  429. PROCEDURE TSwapStream.Reset;
  430.   VAR
  431.     i : INTEGER;
  432.   BEGIN
  433.     FOR i := 0 TO StreamColl.Count - 1 DO
  434.       PStream(StreamColl.At(i))^.Reset;
  435.  
  436.     TStream.Reset;
  437.   END;
  438.  
  439.  
  440. PROCEDURE TSwapStream.Read (VAR Buf; Count: WORD);
  441.   VAR
  442.     p : POINTER;
  443.     c : LONGINT;
  444.   BEGIN
  445.     IF Status <> stOk THEN EXIT;
  446.     Reset;
  447.  
  448.     p := @Buf;
  449.     WHILE (Count > 0) AND (Status = stOk) DO
  450.       BEGIN
  451.  
  452.         c := 0;
  453.         WHILE c = 0 DO
  454.           BEGIN
  455.  
  456.             c := PStream(StreamColl.At(CurrentStream))^.GetSize;
  457.             c := c -
  458.                  PStream(StreamColl.At(CurrentStream))^.GetPos;
  459.  
  460.             IF c = 0 THEN
  461.               BEGIN
  462.                 INC(CurrentStream);
  463.                 IF CurrentStream > LastStream THEN
  464.                   BEGIN
  465.                     Error(stReadError, CurrentStream);
  466.                     DEC(CurrentStream);
  467.                     EXIT;
  468.                   END
  469.                 ELSE
  470.                   PStream(StreamColl.At(CurrentStream))^.Seek(0);
  471.               END;
  472.  
  473.           END;
  474.  
  475.         IF c > Count THEN c := Count;
  476.  
  477.         PStream(StreamColl.At(CurrentStream))^.Read(p^, c);
  478.  
  479.         IF PStream(StreamColl.At(CurrentStream))^.Status <> stOk THEN
  480.           BEGIN
  481.             Error(PStream(StreamColl.At(CurrentStream))^.Status, CurrentStream);
  482.             EXIT;
  483.           END;
  484.  
  485.         DEC(Count, c);
  486.         IncPtr(p, c);
  487.  
  488.       END;
  489.   END;
  490.  
  491.  
  492. PROCEDURE TSwapStream.Write (VAR Buf; Count: WORD);
  493.   VAR
  494.     p : POINTER;
  495.     c : LONGINT;
  496.     Pos  : LONGINT;
  497.     Size : LONGINT;
  498.     PleaseQuanto : BOOLEAN;
  499.   BEGIN
  500.     IF Status <> stOk THEN EXIT;
  501.  
  502.     Reset;
  503.  
  504.     p            := @Buf;
  505.     PleaseQuanto := FALSE;
  506.  
  507.     WHILE (Count > 0) AND (Status = stOk) DO
  508.       BEGIN
  509.  
  510.         c := 0;
  511.         WHILE c = 0 DO
  512.           BEGIN
  513.  
  514.             c := PStream(StreamColl.At(CurrentStream))^.GetSize -
  515.                  PStream(StreamColl.At(CurrentStream))^.GetPos;
  516.  
  517.             IF c = 0 THEN
  518.               BEGIN
  519.                 IF CurrentStream = LastStream THEN
  520.                   BEGIN
  521.                     IF PleaseQuanto THEN
  522.                       c := SwapQuanto
  523.                     ELSE
  524.                       c := Count;
  525.                   END
  526.                 ELSE
  527.                   BEGIN
  528.                     INC(CurrentStream);
  529.                     PStream(StreamColl.At(CurrentStream))^.Seek(0);
  530.                   END;
  531.               END;
  532.  
  533.           END;
  534.  
  535.         IF c > Count THEN c := Count;
  536.  
  537.         Pos  := PStream(StreamColl.At(CurrentStream))^.GetPos;
  538.         Size := PStream(StreamColl.At(CurrentStream))^.GetSize;
  539.  
  540.         PStream(StreamColl.At(CurrentStream))^.Write(p^, c);
  541.  
  542.         IF PStream(StreamColl.At(CurrentStream))^.Status <> stOk THEN
  543.           BEGIN
  544.             PStream(StreamColl.At(CurrentStream))^.Reset;
  545.             PStream(StreamColl.At(CurrentStream))^.Seek(Size);
  546.             PStream(StreamColl.At(CurrentStream))^.Reset;
  547.             PStream(StreamColl.At(CurrentStream))^.Truncate;
  548.             PStream(StreamColl.At(CurrentStream))^.Reset;
  549.             PStream(StreamColl.At(CurrentStream))^.Seek(Pos);
  550.             PStream(StreamColl.At(CurrentStream))^.Reset;
  551.             IF NOT PleaseQuanto THEN
  552.               BEGIN
  553.                 PleaseQuanto := TRUE;
  554.                 Reset;
  555.                 c := 0;
  556.               END
  557.             ELSE
  558.               BEGIN
  559.                 PleaseQuanto := FALSE;
  560.                 INC(LastStream);
  561.                 IF LastStream < StreamColl.Count THEN
  562.                   BEGIN
  563.                     Reset;
  564.                     c := 0;
  565.                   END
  566.                 ELSE
  567.                   BEGIN
  568.                     Error(PStream(StreamColl.At(CurrentStream))^.Status, CurrentStream);
  569.                     EXIT;
  570.                   END;
  571.               END;
  572.           END;
  573.  
  574.         DEC(Count, c);
  575.         IncPtr(p, c);
  576.  
  577.       END;
  578.   END;
  579.  
  580.  
  581.  
  582.  
  583. END.
  584.